#ifndef JDBMODULE_H
#define JDBMODULE_H
#include "msado15_tlh.h"
#include <stdint.h>
#include <string>
#include <memory>
#include <wx/string.h>

/*

if not exists(select id from test_tb where id='1')
    INSERT INTO TEST_TB (id,name,sex,birthday) VALUES('1','Mohammad','21','2019-01-01')
else
    update TEST_TB set name='Mohammad',sex='21',birthday='2019-01-01' where id='1'


*/

namespace ado{
    typedef ADODB::_ConnectionPtr ConnectionPtr;
    typedef ADODB::_RecordsetPtr    RecordsetPtr;
    typedef ADODB::_CommandPtr  CommandPtr;
    typedef ADODB::FieldsPtr     FieldsPtr;
    typedef ADODB::FieldPtr     FieldPtr;
    typedef ADODB::ParametersPtr ParametersPtr;
    typedef ADODB::_ParameterPtr ParameterPtr;
    ConnectionPtr newHisCon(int nn=ADODB::adConnectUnspecified);

    inline void reset_command(CommandPtr & cmd)
    {
        ConnectionPtr con=cmd->GetActiveConnection();
        cmd.Release();
        cmd.CreateInstance("ADODB.Command");
        cmd->PutActiveConnection(_variant_t(con.GetInterfacePtr()));
    }
    inline void reset_command(CommandPtr & cmd,ConnectionPtr con)
    {
        cmd.Release();
        cmd.CreateInstance("ADODB.Command");
        cmd->PutActiveConnection(_variant_t(con.GetInterfacePtr()));
    }

    inline ConnectionPtr newConnection()
    {
        ConnectionPtr con;
        con.CreateInstance("ADODB.Connection");
        return con;
    }

    inline CommandPtr newCommand(ConnectionPtr con)
    {
        CommandPtr cmd;
        cmd.CreateInstance("ADODB.Command");
        cmd->PutActiveConnection(_variant_t(con.GetInterfacePtr()));
        return cmd;
    }



    void ShowError(const wxString & errmsg);
    void ShowError(_com_error & e);
    inline void ShowError(const wchar_t * errmsg)
    {
        ShowError(wxString(errmsg));
    }
    inline void ShowError(const std::wstring & errmsg)
    {
        ShowError(wxString(errmsg));
    }
    inline bool is_null(const _variant_t & data)
    {
        return data.vt==VT_NULL || data.vt==VT_EMPTY;
    }
}



inline _bstr_t ws2bstr(const std::wstring & str)
{
    return _bstr_t(str.data());
}
inline _bstr_t s2bstr(const std::string & str)
{
    return _bstr_t(str.data());
}





template<typename ADO_FIELD,typename TSTREAM>
uint32_t AdoReadBlob(ADO_FIELD&pf,TSTREAM & buf)
{
    uint32_t sz=pf->GetActualSize();
    if(sz)
    {
        _variant_t var;
        do
        {
            uint32_t cz=4096<=sz?4096:sz;// std::max<uint32_t>(4096,sz);
            var=pf->GetChunk(cz);

            sz-=cz;
            char* pdata;
            SafeArrayAccessData(var.parray,(void**)&pdata);
            buf.write(pdata,cz);
            SafeArrayUnaccessData(var.parray);
        }while(sz);
    }
    return sz;
}
template<typename ADO_FIELD,typename TSTREAM>
uint32_t AdoWriteBlob(ADO_FIELD&pf,TSTREAM & buf)
{
    uint32_t sz=0;
    uint32_t cz;
    _variant_t var;
    var.vt=VT_ARRAY | VT_UI1;
    SAFEARRAYBOUND sfb[1];
    sfb[0].cElements=4096;
    sfb[0].lLbound=0;
    var.parray=SafeArrayCreate(VT_UI1,1,sfb);
    char* pdata;
    do
    {
        SafeArrayAccessData(var.parray,(void**)&pdata);
        buf.read(pdata,4096);
        SafeArrayUnaccessData(var.parray);
        cz=buf.gcount();
        if(cz)
        {
            pf->AppendChunk(var);
            sz+=cz;
        }else
        {
            break;
        }
    }while(!buf.eof());
    return sz;
}
extern _variant_t vtMissing;
extern _bstr_t EmptyString;
const char* dataType2string(ADODB::DataTypeEnum tp);

#endif // JDBMODULE_H
